>(以 Nexterm 为例)
## 一、背景与目标
在使用 **Docker Compose** 部署服务时,常见的数据持久化方式有两种:
1. **Docker Volume(命名卷)**
2. **Bind Mount(绑定宿主机目录)**
本次目标是:
- 从旧服务器迁移 Nexterm 服务
- **导出 Docker Compose 自动创建的 volume 中的数据**
- 在新服务器中,**改为使用当前目录下的 `./nexterm` 作为数据目录**
- 确保 **用户、配置、数据完整无损**
---
## 二、问题现象:导出的 volume 是空的?
### 现象
- `docker volume ls` 能看到 volume
- `docker run -v nexterm:/data` 打包成功
- 但生成的 `tar.gz` 只有 **几十字节**
- 新服务器解压后目录是空的
### 关键线索
```bash
docker volume ls | grep nexterm
local nexterm_nexterm
```
而导出时使用的是:
```bash
-v nexterm:/data
```
---
## 三、根因解析:Docker Compose 的 volume 命名规则
### 1️⃣ Compose 不会直接使用你写的 volume 名
在 `docker-compose.yml` 中:
```yaml
volumes:
nexterm:
```
**Docker Compose 实际创建的 volume 名是:**
```text
<项目名>_
```
本例中:
|项目|值|
|---|---|
|Compose 项目名|`nexterm`(目录名)|
|volume 名|`nexterm`|
|实际 volume|`nexterm_nexterm`|
---
### 2️⃣ 为什么不会报错?
当你执行:
```bash
docker run -v nexterm:/data ...
```
如果 `nexterm` 不存在:
- Docker 会 **自动创建一个新的空 volume**
- 命令执行成功
- 但打包的是 **空数据**
👉 这是一个**非常容易踩坑**、而且**不会给任何错误提示**的点。
---
## 四、如何确认容器正在使用的真实 volume(推荐方法)
### 方法一:看 volume 列表
```bash
docker volume ls
```
### 方法二(最稳妥):从容器反查
```bash
docker inspect nexterm-nexterm-1 \
--format '{{ range .Mounts }}{{ if eq .Type "volume" }}{{ .Name }}{{ end }}{{ end }}'
```
输出的 **就是你必须使用的 volume 名**。
---
## 五、正确导出 Docker Volume 数据(旧服务器)
### 1️⃣ 使用真实 volume 名导出
```bash
docker run --rm \
-v nexterm_nexterm:/data \
-v $(pwd):/backup \
busybox \
tar czf /backup/nexterm-volume-backup.tar.gz -C /data .
```
### 2️⃣ 校验备份是否正常
```bash
ls -lh nexterm-volume-backup.tar.gz
```
- ❌ 几十字节 → 一定有问题
- ✅ 几十 KB / 几 MB → 正常
---
## 六、在新服务器中恢复到 Bind Mount 目录
### 1️⃣ 创建目标目录
```bash
mkdir -p /opt/docker/nexterm/nexterm
```
### 2️⃣ 解压数据
```bash
tar xzf nexterm-volume-backup.tar.gz -C /opt/docker/nexterm/nexterm
```
解压后结构示例:
```text
nexterm/
├── logs/
├── nexterm.db
└── sources/
```
---
## 七、修改 docker-compose.yml(从 Volume → Bind Mount)
### 原配置(命名卷)
```yaml
volumes:
- nexterm:/app/data
```
### 修改后(绑定目录)
```yaml
services:
nexterm:
image: germannewsmaker/nexterm:1.0.5-OPEN-PREVIEW
container_name: nexterm
restart: always
ports:
- "6989:6989"
environment:
ENCRYPTION_KEY: "your-key"
volumes:
- ./nexterm:/app/data
```
⚠️ 注意事项:
- 删除 `volumes:` 全局定义
- 确保 `./nexterm` **已存在并且有数据**
- Compose 执行目录必须是 `docker-compose.yml` 所在目录
---
## 八、启动与验证
```bash
docker compose up -d
```
检查状态:
```bash
docker compose ps
docker logs -f nexterm
```
访问 Web 界面后确认:
- 用户是否存在
- 配置是否完整
- 历史数据是否正常
---
## 九、为什么推荐迁移到 Bind Mount?
|对比项|Docker Volume|Bind Mount|
|---|---|---|
|数据可见性|❌|✅|
|备份便利性|一般|极佳|
|可控性|中|高|
|适合长期运维|一般|**非常适合**|
绑定目录后,备份极其简单:
```bash
tar czf nexterm-backup-$(date +%F).tar.gz nexterm/
```
或直接纳入你的 `rclone / restic / borg` 体系。
---
## 十、经验总结(重点)
> **Docker Compose 中,volume 的真实名字 ≠ yml 里写的名字**
记住一句话即可避免 90% 的坑:
> **凡是用 Compose 的 volume,先用 `docker volume ls` 或 `docker inspect` 确认真实名称,再操作**
---
## 十一、延伸建议(下一步可做)
- 为所有 Docker 服务统一目录规范
`/opt/docker/
- 数据目录全部使用 bind mount
- Volume 仅用于临时 / cache / 中间层
- 给每个服务写一个 `backup.sh`
---